#pragma once
#include<memory>
#include<string>
#include<iostream>
#include"Mutex.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>
#include <time.h>
#include<sstream>
#include<fstream>

using namespace LockModule;
namespace LogModule
{

    class LogStrategy
    {
    public:
        virtual ~LogStrategy()=default;//设为虚函数，重写后可以实现多态,用父类指针或引用接收子类指针或引用且可以调用子类的重写方法
        virtual void SyncLog(const std::string &message) = 0;//纯虚函数，不重写就报错

    };

    class ConsoleLogStrategy:public LogStrategy//输出到控制台
    {
    public:
        void SyncLog(const std::string &message)
        {
            LockGuard  guard(_mutex);
            std::cout<<message<<std::endl;
        }
    private:
        Mutex _mutex;
    };

    const std::string defaultlogpath = "./";
    const std::string defaultlogname = "log.txt";

    class FileLogStrategy:public LogStrategy
    {
    public:
        FileLogStrategy(const std::string& logpath=defaultlogpath,const std::string& logname=defaultlogname)
        :_logpath(logpath)
        ,_logname(logname)
        {}

        void SyncLog(const std::string &message)
        {
            LockGuard  guard(_mutex);//自动上锁解锁
            std::string log=_logpath+_logname;
            std::ofstream out(log,std::ios::app);
            out << message << std::endl;
            out.close();
        }

    private:    
        std::string _logpath;
        std::string _logname;
        Mutex _mutex;//锁在初始化队列初始化完成，lockguard智能指针智能的是上锁和解锁

    };

    enum class LogLevel
    {
        DEBUG = 1,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    std::string LevelToString(LogLevel level)
    {
        switch(level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::WARNING:
            return " WARNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return "None";
        }
    }

    std::string getcurrtime()
    {
        time_t t=::time(nullptr);
        struct tm curr;
        localtime_r(&t,&curr);//可重入
        char buffer[1024];
        snprintf(buffer,sizeof(buffer),"%4d-%02d-%02d %02d:%02d:%02d",
        curr.tm_year+1900,
        curr.tm_mon+1,
        curr.tm_mday,
        curr.tm_hour,
        curr.tm_min,
        curr.tm_sec);
        return buffer;
    }
    //日志类
    class Logger
    {
    public:
        Logger()
        {
            _strategy=std::make_shared<ConsoleLogStrategy>();
        }

        void EnableConsoleLog()
        {
            _strategy=std::make_shared<ConsoleLogStrategy>();
        }

        void EnableFileLog()
        {
            _strategy=std::make_shared<FileLogStrategy>();
            
        }

        class LogMessage//这个内部类才是打印日志的关键
        {
        public:
            LogMessage(LogLevel level,const std::string &filename,int line,Logger& logger)
            :_currtime(getcurrtime())
            ,_level(level)
            ,_pid(::getpid())
            ,_filename(filename)
            ,_line(line)
            ,_logger(logger)
            {
                std::stringstream ss;
                ss<<"["<<_currtime<<"]"
                    <<"["<<LevelToString(_level)<<"]"
                    <<"[" << _pid << "]"
                    <<"[" <<_filename <<"]"
                    <<"[" << _line << "] -";
                _loginfo=ss.str();
            }

            template <typename T>
            LogMessage &operator<<(const T& info)
            {
                std::stringstream ss;
                ss<<info;
                _loginfo+=ss.str();
                return *this; 
            }

            ~LogMessage()
            {
                _logger._strategy->SyncLog(_loginfo);
            }
        private:
            std::string _currtime;
            LogLevel _level;      //日志等级
            pid_t _pid;           //进程pid
            std::string _filename;//文件名
            int _line;            //行号
            Logger& _logger;      //调用的日志策略
            std::string _loginfo; //完整日志信息
        };


        LogMessage operator()(LogLevel level,const std::string &filename,int line)
        {
            return LogMessage(level,filename,line,*this);//创建一个临时对象，最终在main中得到一个匿名对象

        }
    private:
        std::shared_ptr<LogStrategy> _strategy;//一个父类的智能指针,可接收两种子类的智能指针,日志的刷新方案

    };

    Logger logger;

#define LOG(level) logger(level,__FILE__,__LINE__)//operator()   临时对象，智能指针的思路
#define ENABLE_CONSOLE_LOG() logger.EnableConsoleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()


}